package request

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"reflect"
	"strings"
	"sync"
)

type Request struct {
	ApiUrl   string   // 【必填】请求地址
	HttpType string   //【非必填】POST GET 默认POST
	Header   sync.Map //【非必填】 自定义请求头，传入则会覆盖掉默认的
	SendData any      //【非必填】请求数据 map[string]any 或结构体
}

func NewRequest(apiUrl string, httpType string) *Request {
	instance := &Request{ApiUrl: apiUrl, HttpType: httpType, SendData: nil}
	//设置默认值
	instance.Header.Store("Content-Type", "application/json")
	return instance
}

// NewRequestWithData 创建新的请求
func NewRequestWithData(apiUrl string, httpType string, sendData any) *Request {
	instance := NewRequest(apiUrl, httpType)
	instance.SendData = sendData
	return instance
}

// SetHeader 设置（或添加）请求头
func (s *Request) SetHeader(k string, val string) *Request {

	s.Header.Store(k, val)
	return s
}

// Send 发送HTTP请求，并根据Content-Type处理请求体。
func (s *Request) Send() (*http.Response, error) {
	var err error
	var buffer *bytes.Buffer

	// 根据Content-Type处理请求体
	contentType, _ := s.Header.Load("Content-Type")
	contentTypeStr := contentType.(string)
	switch strings.TrimSpace(contentTypeStr) {
	case "application/json":
		if s.SendData != nil {
			jsonData, err := json.Marshal(s.SendData)
			if err != nil {
				return nil, err
			}
			buffer = bytes.NewBuffer(jsonData)
		}
	case "application/x-www-form-urlencoded":
		if s.SendData != nil {
			values := url.Values{}
			if err := s.encodeFormData(values, s.SendData); err != nil {
				return nil, err
			}
			buffer = bytes.NewBufferString(values.Encode())
		}
	default:
		// 如果没有指定或不支持的Content-Type，直接使用原始数据
		if s.SendData != nil {
			if data, ok := s.SendData.([]byte); ok {
				buffer = bytes.NewBuffer(data)
			} else {
				return nil, fmt.Errorf("unsupported Content-Type: %s", contentType)
			}
		}
	}

	// 构造请求
	req, err := http.NewRequest(s.HttpType, s.ApiUrl, buffer)
	if err != nil {
		return nil, err
	}

	s.Header.Range(func(key, value interface{}) bool {
		req.Header.Set(key.(string), value.(string))
		return true // 返回 true 表示继续遍历，返回 false 则停止
	})
	// 发送请求
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}

	return resp, nil
}

// encodeFormData 将结构体转换为url.Values。
func (s *Request) encodeFormData(values url.Values, data interface{}) error {
	v := reflect.ValueOf(data)
	if v.Kind() == reflect.Ptr {
		v = v.Elem()
	}
	if v.Kind() != reflect.Struct {
		return fmt.Errorf("data should be a struct or a pointer to a struct")
	}

	t := v.Type()
	for i := 0; i < v.NumField(); i++ {
		field := t.Field(i)
		value := v.Field(i).Interface()
		tag := field.Tag.Get("json")
		if tag == "" {
			continue
		}
		values.Set(tag, fmt.Sprintf("%v", value))
	}

	return nil
}
